﻿using System;
using SportTraining.Core;
using SportTraining.Core.Services;

using SportTraining.MVVM.Model;
using SportTraining.MVVM.View;

namespace SportTraining.MVVM.ViewModel.Impl
{
    public class PaymentPageViewModel : PageViewModel<PaymentPageViewModel>, IPaymentPageViewModel
    {
        private readonly IPaymentProcedureModel model;

        public PaymentPageViewModel(IMainWindowViewModel mainWindowViewModel, IPaymentProcedureModel model)
            : base(mainWindowViewModel)
        {
            this.model = model;

            canBack = true;

            paymentItem = (PaymentItemViewModel) mainWindowViewModel.GetObject(KeyConstants.PaymentItemKey);

            Back = new Command(param => CancelWaitMoney());

            Forward = new Command(param => Pay());
            
            StartWaitMoney();
        }

        #region Implementation of IPaymentPageViewModel

        private readonly PaymentItemViewModel paymentItem;
        public IPaymentItemViewModel PaymentItem
        {
            get { return paymentItem; }
        }

        private bool canBack;
        public bool CanBack
        {
            get { return canBack; }
            set { canBack = value;
                FirePropertyChanged(type => type.CanBack);
            }
        }

        private bool canForward;
        public bool CanForward
        {
            get { return canForward; }
            set
            {
                canForward = value;
                FirePropertyChanged(type => type.CanForward);
            }
        }

        #endregion

        #region events from model

        private void ReceiveMoneyEvent(object sender, BillAcceptorEventArgs e)
        {
            PaymentItem.FeeMoney += e.ReceiveMoney;

            CanBack = PaymentItem.FeeMoney == 0;

            CanForward = !CanBack;

            if (PaymentItem.RestMoney == 0)
            {
                Pay();
            }
        }

        private void ErrorEvent(object sender, TerminalDeviceErrorEventArgs e)
        {
            var error =
                new SportTrainigException(string.Format("Ошибка терминального устройства типа - {0}.\n{1}", e.DeviceType,
                                                        e.TerminalDeviceException));

            // сохраняем ошибку чтоб показать потом на странице ошибке
            mainWindowViewModel.SaveObject(KeyConstants.ErrorKey, error);

            OnError.Execute(null);
        }

        #endregion

        #region private method

        private void Pay()
        {
            CancelWaitMoney();

            try
            {
                model.SavePayment(paymentItem.Payment);

                mainWindowViewModel.CurrentPageUri = AppUri.CheckPrintPage;
            }
            catch (Exception err)
            {
                mainWindowViewModel.SaveObject(KeyConstants.ErrorKey, err);

                OnError.Execute(null);
            }
        }

        private void StartWaitMoney()
        {
            model.ReceiveMoneyEvent += ReceiveMoneyEvent;
            model.ErrorEvent += ErrorEvent;

            model.StartWaitMoney();
        }

        private void CancelWaitMoney()
        {
            model.StopWaitMoney();

            model.ReceiveMoneyEvent -= ReceiveMoneyEvent;
            model.ErrorEvent -= ErrorEvent;

            mainWindowViewModel.CurrentPageUri = AppUri.SectionSelectPage;
        }

        #endregion
    }
}